// Experimenting with a different code formatting style.

package server;

import FileHandling.FileOps;
import java.net.*;
import java.io.*;

/**
 * Handles listening for clients and file transfers.
 * 
 * @author Lewis Marhin and John Gray-Spence
 */
public class ServerOps {

    private Socket sock;
    private ServerSocket serverSock;
    private OutputStream client;
    private final int serverPortNum = 1337;
    private static boolean isServing = false;

    /**
     * Constructor, calls for the admin listener thread to start.
     */
    public ServerOps() {
        AdminHandler adminThread = new AdminHandler();
        adminThread.start();
    }

    /**
     * Creates socket and calls for the client listener thread.
     * 
     * @return Message confirming/denying server startup (or error message).
     */
    public String startServer() {
        if( !isServing ) {
            try {
                    serverSock = new ServerSocket( serverPortNum );
                    new ClientListener().start();
                    isServing = true;
                } catch ( BindException e ) {
                    System.out.println( "Server is already running." );
                } catch ( IOException e ) {
                    return "An IO error has occured. \nError: \n" + e.toString();
                }
            return "Server started.";
        } else if ( isServing ) {
            return "Server is already running.";
        }

        return null;
    }

    /**
     * Listens for clients connecting to the server. Generates a new thread to handle their requests.
     */
    public class ClientListener extends Thread {
        // Loop listening for clients (refer to ass2 of last year)
        // Requires: o socket things
        //           o soemthing else maybe

        @Override
        public void run() {
            try {
                sock = serverSock.accept();
                client = sock.getOutputStream();

                System.out.println( "Client connected (" + sock.getInetAddress() + ")." );

                new ClientHandler().start();
            } catch ( IOException e ) {
                System.out.println( "An error has occured while connecting to" + " client." );
                System.out.println( e.toString() );
            }
        }
    }

    /**
     * Handles a particular client's requests. Sends and recieves mindmaps.
     */
    public class ClientHandler extends Thread {
        // Loop waiting for client commands, since client cannot send any other
        // commands while transmitting data anyway, this thread will also send
        // data to the client
        // Requires: o send maps
        //           o receive maps
        //           o erase maps
        //           o receive ratings

        @Override
        public void run() {
            try {
                InputStreamReader inStream = new InputStreamReader( sock.getInputStream() );
                BufferedReader reader = new BufferedReader( inStream );

                OutputStreamWriter outStream = new OutputStreamWriter( sock.getOutputStream() );
                BufferedWriter writer = new BufferedWriter( outStream );

                boolean connected = true;

                String command = reader.readLine();

                while( connected ) {
                    if ( command.equals( "SendRandomMapsToRate" ) ) {
                        // Gets files to send
                        MapOrganising.ListObject fileList[] = MapOrganising.ListMaker.getRandomList();

                        // Number of files to send is sent first
                        writer.write( fileList.length );
                        writer.newLine();

                        for ( int i = 0; i < fileList.length; i++) {
                            // Catagories of file is sent second
                            writer.write( fileList[i].getCat() );
                            writer.newLine();
                            // Sends file contents
                            writer.write( FileOps.readFile( fileList[i].getFname() ) );
                            writer.newLine();
                            // Send file name
                            writer.write( fileList[i].getFname() );
                        }
                    } else if ( command.equals( "SendingRatedMaps" ) ) {
                        // Receives number of maps first
                        int q = Integer.parseInt( reader.readLine() );

                        // Receive map, it's catagories and it's rating and it's file name
                        for( int p = 0; p < q; p++ ) {
                            String tmpR = reader.readLine(); // rating
                            String tmpC = reader.readLine(); // catagories
                            String tmpM = reader.readLine(); // map
                            String tmpF = reader.readLine(); // file name

                            MapOrganising.ListMaker.updateMasterList( tmpF, tmpM, tmpC, tmpR );
                        }
                        
                    } else if (command.equals( "SendingNewMap" ) ) {
                        reader.readLine();
                    } else if ( command.equals( "Quit" ) ) {
                        // Disconnect
                        connected = false;
                    }
                }
                reader.close();
                writer.close();
            } catch( Exception e ) {
                System.out.println( "Error" );
                System.out.println( e.toString() );
            }
        }
    }

    /**
     * Handles a particular administrators login and subsequent requests.
     */
    public class AdminHandler extends Thread {
        // Awaits the administrators password then handles their options
        // Requires: o password handling
        //           o delete low rated maps
        //           o startup/shutdown server

        // if password is correct {
        //      loop start
        //          display menu
        //          wait for input
        //      loop end when logout is pressed
        // else
        //      display incorrect pass msg
    }
}
